package com.carrot.newsgallery.controller;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.carrot.newsgallery.common.R;
import com.carrot.newsgallery.entity.UserInfo;
import com.carrot.newsgallery.service.UserInfoService;
import com.carrot.newsgallery.utils.HttpUtil;
import com.carrot.newsgallery.utils.MyDatabaseException;
import com.carrot.newsgallery.utils.ReturnCode;
import com.carrot.newsgallery.utils.TokenUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.util.DigestUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.net.URLEncoder;
import java.time.LocalDate;
import java.util.UUID;

@Slf4j
@Api(description = "用户相关")
@RestController
@RequestMapping("/user")
public class UserInfoController {

    @Autowired
    private UserInfoService userInfoService;

    @Value("${path.root-path}")
    private String rootpath;

    @PostMapping("/register")
    public R register(@RequestBody UserInfo userInfo) throws MyDatabaseException {

        //先检查该用户是否已经存在
        UserInfo userExist = userInfoService.getByUsername(userInfo.getUsername());
        if (userExist != null) {
            return R.fail(ReturnCode.USER_ALREADY_EXIST,"用户已存在!");
        }

        //不存在则注册该用户
        String uuid = UUID.randomUUID().toString().replaceAll("-","");
        String password = userInfo.getPassword();
        password = DigestUtils.md5DigestAsHex(password.getBytes());

        userInfo.setPassword(password);
        userInfo.setAlias(userInfo.getUsername());  //用户默认昵称为用户名
        userInfo.setUuid(uuid);
        userInfo.setStatus(0);  //默认处于开放状态
        userInfo.setCreateDate(LocalDate.now());

        //将该用户录入到数据库中
        boolean saveOk = userInfoService.save(userInfo);

        if (saveOk)
            return R.success(null,"用户创建成功");
        else {
            throw new MyDatabaseException(MyDatabaseException.errorCode.FAILURE);
        }
    }

    @PostMapping("/login")
    public R login(HttpServletRequest request, HttpServletResponse response,
                   @RequestBody UserInfo userInfo){
        //如果未登录,则对用户名和密码进行匹配
        //先对密码进行加密
        String password = userInfo.getPassword();
        password = DigestUtils.md5DigestAsHex(password.getBytes());

        //查询数据库
        UserInfo one = userInfoService.getByUsername(userInfo.getUsername());

        //没有查询结果说明查询失败
        if (one == null){
            return R.fail(ReturnCode.USER_NOT_EXIST,"该用户不存在,请确认用户名!");
        }

        //密码匹配失败则返回
        if (!one.getPassword().equals(password)){
            return R.fail(ReturnCode.USER_PASSWORD_ERROR,"密码错误,请确认密码!");
        }

        //账号封禁时拒绝登录
        if (one.getStatus()!=0){
            return R.fail(ReturnCode.USER_BANNED,"该账户处于封禁状态,禁止登陆!");
        }

        //没有其他问题,允许登录,设置session属性
        log.info("用户"+one.getUuid()+"已登陆");
        String token = TokenUtil.genToken(one.getUserInfoId(), one.getPassword());
        return R.success(token,"登陆成功");
    }

    @PutMapping("/logout")
    @ApiOperation("用户退出")
    public R logout(HttpServletRequest request){
        return R.success(null,"退出成功");
    }

    @GetMapping
    @ApiOperation("获取用户本人的信息")
    public R getInfo(HttpServletRequest request){
        String token = HttpUtil.getToken(request);
        TokenUtil tokenUtil = new TokenUtil();
        UserInfo user = tokenUtil.getUser(token);
        return R.success(UserInfo.extractPublicInfo(user,rootpath),"查询成功");
    }

    /**
     * 负责除了头像路径外的其他所有信息的更新
     * @param userInfo
     * @return
     */
    @PutMapping("/update")
    @ApiOperation("负责除了头像路径外的其他所有信息的更新")
    public R updateUserInfo(HttpServletRequest request, @RequestParam String newPassword,
                            @RequestBody UserInfo userInfo){
        String token = HttpUtil.getToken(request);
        TokenUtil tokenUtil = new TokenUtil();
        UserInfo userExist = tokenUtil.getUser(token);

        //检查该用户是否在更新自己的信息
        if (userExist.getUserInfoId() != userInfo.getUserInfoId()){
            return R.fail(ReturnCode.USER_ILLEGAL_OPERATION,"非法操作,您正在尝试更新其他用户的信息!");
        }

        //如果要修改密码, 那么就要先校验密码是否正确
        if (StringUtils.isNotEmpty(newPassword) && !newPassword.equals("1") ){
            String password = DigestUtils.md5DigestAsHex(userInfo.getPassword().getBytes());
            if (!password.equals(userExist.getPassword()))
                return R.fail(ReturnCode.USER_ILLEGAL_OPERATION,"密码错误,请重新输入");
            //正确,则写入新密码
            userExist.setPassword(DigestUtils.md5DigestAsHex(newPassword.getBytes()));
        }

        //更新信息
        if (userInfo.getAlias() != null)
            userExist.setAlias(userInfo.getAlias());
        if (userInfo.getPhone() != null)
            userExist.setAlias(userInfo.getAlias());
        if (userInfo.getEmail() != null)
            userExist.setEmail(userInfo.getEmail());

        log.info("");

        LambdaUpdateWrapper<UserInfo> luw = new LambdaUpdateWrapper<>();
        luw.eq(true,UserInfo::getUserInfoId,userInfo.getUserInfoId());

        //写入数据库
        boolean ok = userInfoService.update(userExist,luw);
        if (ok) {
            return R.success(null,"更新成功");
        }
        else{
            return R.fail(ReturnCode.SERVER_ERROR,"无法保存该数据,请检查是否符合要求!");
        }
    }

    /**
     * 头像的上传与更新
     * @param request
     * @param file
     * @return
     * @throws IOException
     */
    @PostMapping("/avatar")
    @ApiOperation("用户的头像上传更新")
    public R avatarUpdate(HttpServletRequest request,
                          @RequestPart MultipartFile file) throws IOException {
        String token = HttpUtil.getToken(request);
        TokenUtil tokenUtil = new TokenUtil();
        UserInfo user = tokenUtil.getUser(token);
        String uuid = user.getUuid();

        if (!file.isEmpty()){
            String originalFilename = file.getOriginalFilename();
            int last = originalFilename.lastIndexOf(".");
            if (last == -1){
                return R.fail(ReturnCode.DATA_ERROR,"数据拓展名异常,请检查文件后缀!");
            }
            String path = "/data/users/" + uuid + "/file" + originalFilename.substring(last);
            File filestrem = new File(path);
            if (!filestrem.getParentFile().exists()){
                filestrem.getParentFile().mkdirs();
            }
            file.transferTo(filestrem);

            //更新数据库
            LambdaUpdateWrapper<UserInfo> luw = new LambdaUpdateWrapper<>();
            luw.eq(true,UserInfo::getUserInfoId,user.getUserInfoId())
                            .set(true,UserInfo::getAvatar,path);
            userInfoService.update(luw);
            log.info("new file at:"+path);
            return R.success(rootpath+"/user/public/"+uuid,"头像上传成功");
        }

        else
            return R.fail(ReturnCode.DATA_ERROR,"请勿提交空数据!");
    }

    /**
     * 获取其他用户的头像
     * @param response
     * @param uuid
     * @return
     */
    @GetMapping("/public/{uuid}")
    @ApiOperation("获取其他用户的头像")
    public R downloadAvatar(HttpServletResponse response,
                            @PathVariable String uuid){
        LambdaQueryWrapper<UserInfo> lqw = new LambdaQueryWrapper<>();
        lqw.eq(UserInfo::getUuid,uuid);
        UserInfo one = userInfoService.getOne(lqw);

        String path = one.getAvatar();
        String filename = path.substring(path.lastIndexOf("/")+1);


        if (StringUtils.isEmpty(one.getAvatar())){
            return R.fail(ReturnCode.DATA_ERROR,"该用户尚未设置自定义头像");
        }

        File file = new File(path);

        try {

            ServletOutputStream os = response.getOutputStream();
            response.addHeader("Content-Disposition","attachment;filename="+URLEncoder.encode(filename,"UTF-8"));
            response.setContentType("application/octet-stream");

            os.write(FileUtils.readFileToByteArray(file));
            os.flush();
            os.close();

        } catch (Exception exception) {
//            return R.fail(ReturnCode.SERVER_ERROR,"服务器异常,请稍后重试");
            return null;
        }
        return null;
    }

}
